package com.ruoyi.learn.java.design.pattern.behavior;

/**
 * 状态模式 (State Pattern) 完整示例
 * 模拟一个简单的糖果机 (Gumball Machine)。
 */
public class StatePatternDemo {

    // 1. 定义状态接口
    public interface State {
        void insertQuarter();   // 投币
        void ejectQuarter();    // 退币
        void turnCrank();       // 转动手柄
        void dispense();        // 发放糖果
    }

    // 2. 具体状态类 1: 已售出 (SoldState)
    public static class SoldState implements State {
        private GumballMachine gumballMachine;

        public SoldState(GumballMachine gumballMachine) {
            this.gumballMachine = gumballMachine;
        }

        @Override
        public void insertQuarter() {
            System.out.println("请稍等，我们正在为您发放糖果...");
        }

        @Override
        public void ejectQuarter() {
            System.out.println("抱歉，您已经转了手柄，不能退币。");
        }

        @Override
        public void turnCrank() {
            System.out.println("转动两次不会得到更多糖果！");
        }

        @Override
        public void dispense() {
            gumballMachine.releaseBall();
            if (gumballMachine.getCount() > 0) {
                gumballMachine.setState(gumballMachine.getNoQuarterState());
            } else {
                System.out.println("哎呀，糖果售罄了！");
                gumballMachine.setState(gumballMachine.getSoldOutState());
            }
        }

        @Override
        public String toString() {
            return "正在发放糖果状态";
        }
    }

    // 3. 具体状态类 2: 售罄 (SoldOutState)
    public static class SoldOutState implements State {
        private GumballMachine gumballMachine;

        public SoldOutState(GumballMachine gumballMachine) {
            this.gumballMachine = gumballMachine;
        }

        @Override
        public void insertQuarter() {
            System.out.println("抱歉，糖果已售罄，无法投币。");
        }

        @Override
        public void ejectQuarter() {
            System.out.println("您还没有投币，无法退币。");
        }

        @Override
        public void turnCrank() {
            System.out.println("抱歉，糖果已售罄，无法转动手柄。");
        }

        @Override
        public void dispense() {
            System.out.println("抱歉，无法发放糖果，因为已售罄。");
        }

        @Override
        public String toString() {
            return "售罄状态";
        }
    }

    // 4. 具体状态类 3: 未投币 (NoQuarterState)
    public static class NoQuarterState implements State {
        private GumballMachine gumballMachine;

        public NoQuarterState(GumballMachine gumballMachine) {
            this.gumballMachine = gumballMachine;
        }

        @Override
        public void insertQuarter() {
            System.out.println("您已成功投币！");
            gumballMachine.setState(gumballMachine.getHasQuarterState());
        }

        @Override
        public void ejectQuarter() {
            System.out.println("您还没有投币，无法退币。");
        }

        @Override
        public void turnCrank() {
            System.out.println("请先投币！");
        }

        @Override
        public void dispense() {
            System.out.println("请先投币！");
        }

        @Override
        public String toString() {
            return "未投币状态";
        }
    }

    // 5. 具体状态类 4: 已投币 (HasQuarterState)
    public static class HasQuarterState implements State {
        private GumballMachine gumballMachine;

        public HasQuarterState(GumballMachine gumballMachine) {
            this.gumballMachine = gumballMachine;
        }

        @Override
        public void insertQuarter() {
            System.out.println("您已投过币了，无需再投！");
        }

        @Override
        public void ejectQuarter() {
            System.out.println("您的币已退回。");
            gumballMachine.setState(gumballMachine.getNoQuarterState());
        }

        @Override
        public void turnCrank() {
            System.out.println("您转动了手柄...");
            // 模拟随机失败（10%概率）
            int random = (int) (Math.random() * 10);
            if (random == 0 && gumballMachine.getCount() > 1) {
                System.out.println("哎呀！机器坏了，您的币已退回！");
                gumballMachine.setState(gumballMachine.getNoQuarterState());
            } else {
                gumballMachine.setState(gumballMachine.getSoldState());
            }
        }

        @Override
        public void dispense() {
            System.out.println("您必须先转动手柄！");
        }

        @Override
        public String toString() {
            return "已投币状态";
        }
    }

    // 6. 上下文 (Context): 糖果机
    public static class GumballMachine {
        private State soldOutState;
        private State noQuarterState;
        private State hasQuarterState;
        private State soldState;

        private State state; // 当前状态
        private int count = 0; // 糖果数量

        public GumballMachine(int numberGumballs) {
            soldOutState = new SoldOutState(this);
            noQuarterState = new NoQuarterState(this);
            hasQuarterState = new HasQuarterState(this);
            soldState = new SoldState(this);

            this.count = numberGumballs;
            if (numberGumballs > 0) {
                state = noQuarterState; // 初始状态：未投币
            } else {
                state = soldOutState;  // 初始状态：售罄
            }
        }

        // 将请求委托给当前状态对象
        public void insertQuarter() {
            state.insertQuarter();
        }

        public void ejectQuarter() {
            state.ejectQuarter();
        }

        public void turnCrank() {
            state.turnCrank();
            // 转动后尝试发放（状态机内部逻辑）
            if (state == soldState) {
                state.dispense();
            }
        }

        // 仅由状态对象调用
        void setState(State state) {
            this.state = state;
        }

        void releaseBall() {
            System.out.println("一颗糖果正在发放...");
            if (count != 0) {
                count = count - 1;
            }
        }

        // Getter 方法
        public State getSoldOutState() {
            return soldOutState;
        }

        public State getNoQuarterState() {
            return noQuarterState;
        }

        public State getHasQuarterState() {
            return hasQuarterState;
        }

        public State getSoldState() {
            return soldState;
        }

        public int getCount() {
            return count;
        }

        public State getState() {
            return state;
        }

        @Override
        public String toString() {
            return "\n------ 糖果机 ------\n" +
                    "当前状态: " + state + "\n" +
                    "剩余糖果: " + count + " 颗\n" +
                    "------------------\n";
        }
    }

    // 7. 主方法 (程序入口)
    public static void main(String[] args) {
        // 创建一个有 5 颗糖果的机器
        GumballMachine gumballMachine = new GumballMachine(5);

        System.out.println(gumballMachine);

        // 模拟用户操作
        gumballMachine.insertQuarter();
        System.out.println(gumballMachine);

        gumballMachine.turnCrank();
        System.out.println(gumballMachine);

        gumballMachine.insertQuarter();
        gumballMachine.ejectQuarter();
        gumballMachine.turnCrank();
        System.out.println(gumballMachine);

        // 投币并尝试转动手柄（可能失败）
        gumballMachine.insertQuarter();
        gumballMachine.turnCrank();
        System.out.println(gumballMachine);

        // 继续购买，直到售罄
        while (gumballMachine.getCount() > 0) {
            gumballMachine.insertQuarter();
            gumballMachine.turnCrank();
            System.out.println(gumballMachine);
        }

        // 售罄后尝试操作
        gumballMachine.insertQuarter();
        gumballMachine.turnCrank();
        gumballMachine.ejectQuarter();
    }
}
